package com.pb.wkflow.api.service.impl;

import com.alibaba.fastjson.JSON;
import com.pb.infra.oth.entity.common.Result;
import com.pb.infra.oth.service.BaseService;
import com.pb.infra.oth.util.UserInfo;
import com.pb.wkflow.api.annotation.GlobalWorkflowAnnotation;
import com.pb.wkflow.api.annotation.WfTaskAnnotationService;
import com.pb.wkflow.api.config.TransNodeNameEnum;
import com.pb.wkflow.api.controller.assembler.ProcInstanceAssembler;
import com.pb.wkflow.api.controller.assembler.ProcTaskAssembler;
import com.pb.wkflow.api.controller.request.ProcessInstanceCreateRequest;
import com.pb.wkflow.api.controller.request.ProcessInstanceRequest;
import com.pb.wkflow.api.controller.request.ProcessTaskRequest;
import com.pb.wkflow.api.controller.response.ProcessResponse;
import com.pb.wkflow.api.entity.*;
import com.pb.wkflow.api.mapper.WfSysJsonXmlMapper;
import com.pb.wkflow.api.query.ProcInstanceQuery;
import com.pb.wkflow.api.service.ParticipantService;
import com.pb.wkflow.api.service.ProcInstService;
import com.pb.wkflow.api.service.WfSysProcInfoService;
import com.pb.wkflow.core.config.Constants;
import com.pb.wkflow.core.config.DeleteReasonConstants;
import com.pb.wkflow.core.entity.ActHiCommentEntity;
import com.pb.wkflow.core.entity.ActHiTaskEntity;
import com.pb.wkflow.core.entity.ActRuIdentityLinkEntity;
import com.pb.wkflow.core.entity.PostInfo;
import com.pb.wkflow.core.handler.QueryHandler;
import com.pb.wkflow.core.handler.QueryResultHandler;
import com.pb.wkflow.core.service.*;
import com.pb.wkflow.core.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.camunda.bpm.engine.ProcessEngine;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.history.HistoricActivityInstance;
import org.camunda.bpm.engine.history.HistoricProcessInstance;
import org.camunda.bpm.engine.history.HistoricVariableInstance;
import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
import org.camunda.bpm.engine.impl.core.model.PropertyKey;
import org.camunda.bpm.engine.impl.interceptor.Command;
import org.camunda.bpm.engine.impl.interceptor.CommandContext;
import org.camunda.bpm.engine.impl.interceptor.CommandExecutor;
import org.camunda.bpm.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.camunda.bpm.engine.impl.persistence.entity.TaskEntity;
import org.camunda.bpm.engine.impl.pvm.PvmTransition;
import org.camunda.bpm.engine.impl.pvm.process.ActivityImpl;
import org.camunda.bpm.engine.impl.task.TaskDefinition;
import org.camunda.bpm.engine.repository.ProcessDefinition;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.model.bpmn.BpmnModelInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 苗益辉
 * @date 2022/9/19 10:46
 */
@Slf4j
@Service
public class ProcInstServiceImpl extends BaseService implements ProcInstService {

    @Autowired
    ProcessEngine processEngine;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    WorkflowTaskService workflowTaskService;

    @Autowired
    WorkflowDefinitionService workflowDefinitionService;

    @Autowired
    UserParticipantService userParticipantService;

    @Autowired
    WorkflowInstanceService workflowInstanceService;

    @Autowired
    WorkFlowEngineService workFlowEngineService;

    @Autowired
    WfSysProcInfoService wfSysProcInfoService;

    @Autowired
    ParticipantService participantService;

    @Autowired
    GlobalWorkflowAnnotation workflowAnnotation;

    @Autowired
    WfSysJsonXmlMapper wfSysJsonXmlMapper;

    @Autowired
    QueryHandler queryHandler;

    private void setUserInfo(ProcessInstanceCreateRequest request) {
        UserInfo userInfo = this.getCurrentUserInfo();
        String orgName = userInfo.getOrgName();
        String orgId= userInfo.getOrgId();
        if (StringUtils.isBlank(orgName)) {
            orgId = userInfo.getDeptId();
            orgName = userInfo.getDeptName();
        }
        request.setStartUserId(userInfo.getUserId());
        request.setStartUserName(userInfo.getUserName());
        request.setStartUserOrg(orgId);
        request.setStartUserOrgName(orgName);
        request.setStartUserPos(userInfo.getPostId());
        request.setStartUserRole(String.join(",", userInfo.getRoles()));
    }

    /**
     * 开启流程
     * @param request request
     * @return Result
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProcessResponse startProcess(ProcessInstanceCreateRequest request, boolean flag) {
        String cropId = this.getCurrentUserInfo().getCorpId();
        request.setTenantId(cropId);
        AssertUtils.notEmpty(request.getProcDefKey(), "流程键值不能为空");
        this.setUserInfo(request);
        ProcInstanceAssembler.setGlobalVariablesData(request);

        ProcessDefinition processDefinition;
        List<WfSysJsonXmlEntity> wfSysJsonXmlEntities = wfSysJsonXmlMapper.selectUsedByProcDefKey(
                request.getProcDefKey(),request.getTenantId());
        if (null == wfSysJsonXmlEntities || wfSysJsonXmlEntities.isEmpty()) {
            // 如果没有配置使用中的流程，默认取最新版本的流程
            processDefinition = workflowDefinitionService.findByProcessDefineKeyAndLastVersion(
                    request.getProcDefKey(), request.getTenantId()
            );
        } else {
            WfSysJsonXmlEntity wfSysJsonXmlEntity = wfSysJsonXmlEntities.get(0);
            processDefinition = workflowDefinitionService.findByProcessDefineId(wfSysJsonXmlEntity.getProcDefId());
        }

        AssertUtils.notNull(processDefinition, "流程不存在");

        request.setNowDate(DateUtils.dateToStr(new Date()));

        ProcessInstance processInstance = runtimeService
                .startProcessInstanceById(processDefinition.getId(), request.getGlobalVariables());
        log.info("start is ok processInstanceId :{}",processInstance.getId());

        wfSysProcInfoService.insert(processDefinition, processInstance, request);

        ProcessResponse.ProcessResponseBuilder responseBuilder = ProcessResponse.builder()
                .processDefineId(processDefinition.getId())
                .processDefineKey(processDefinition.getKey())
                .processInstanceId(processInstance.getId())
                .processDefineName(processDefinition.getName());

        List<Task> taskList = workflowTaskService.findTaskList(processInstance.getProcessInstanceId());
        if (CollectionUtils.isNotEmpty(taskList)) {
            Task task = taskList.get(0);
            if (task != null) {
                responseBuilder.currentTaskId(task.getId());
                responseBuilder.currentActivityId(task.getTaskDefinitionKey());
            }
        }

        ProcessResponse response = responseBuilder.build();
        if (flag) {
            WfSysProcInfoEntity wfSysProcInfoEntity = getProcInfo(response.getProcessInstanceId(), "发起申请");
            WfTaskAnnotationService wfTaskAnnotationService = workflowAnnotation.getService(response.getProcessDefineKey());
            wfTaskAnnotationService.submitTask(wfSysProcInfoEntity);
        }

        return response;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ProcessResponse startAndSubmitProcess(ProcessInstanceCreateRequest request) {
        ProcessResponse startResponse = this.startProcess(request, false);
        String currentTaskId = startResponse.getCurrentTaskId();
        List<ActHiTaskEntity> actHiTaskEntities = workflowInstanceService
                .findTaskListByProcessInstanceId(startResponse.getProcessInstanceId());
        if (!actHiTaskEntities.isEmpty()) {
            ActHiTaskEntity actHiTaskEntity = actHiTaskEntities.get(0);
            WorkflowThreadLocalUtil.put("deleteReasonProcInstId", actHiTaskEntity.getProcInstId());
            WorkflowThreadLocalUtil.put("deleteReasonTaskId", actHiTaskEntity.getId());
            WorkflowThreadLocalUtil.put("deleteReason", DeleteReasonConstants.START);
        }
        workflowTaskService.claimTask(currentTaskId, request.getStartUserId());
        workflowTaskService.passProcess(currentTaskId, request.getGlobalVariables());
        userParticipantService.deleteRuIdentityLink(currentTaskId);
        List<Task> taskList = workflowTaskService.findTaskList(startResponse.getProcessInstanceId());
        if (CollectionUtils.isNotEmpty(taskList)) {
            Task task = taskList.get(0);
            if (task != null) {
                startResponse.setProcessInstanceId(task.getProcessInstanceId());
                startResponse.setCurrentActivityId(task.getTaskDefinitionKey());
            }
        }

        WfSysProcInfoEntity wfSysProcInfoEntity = getProcInfo(startResponse.getProcessInstanceId(), "发起申请");
        WfTaskAnnotationService wfTaskAnnotationService = workflowAnnotation.getService(startResponse.getProcessDefineKey());
        wfTaskAnnotationService.submitTask(wfSysProcInfoEntity);
        return startResponse;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void terminateProcess(ProcessInstanceRequest request) {
        String userId = this.getCurrentUserId();
        request.setUserId(userId);
        AssertUtils.notEmpty(request.getProcessInstanceId(), "流程实例id不能为空");
        ProcessInstance processInstance = workflowInstanceService.findByProcessInstanceId(
                request.getProcessInstanceId()
        );
        AssertUtils.notNull(processInstance, "流程实例不存在或已结束");
        workflowInstanceService.setVariables(request.getProcessInstanceId(), request.getVariables());
        workFlowEngineService.terminateProcess(
                request.getProcessInstanceId(),
                request.getComments(),
                request.getTaskId(),
                request.getUserId()
        );
        //更新流程状态
        wfSysProcInfoService.update(request.getProcessInstanceId(), DeleteReasonConstants.TERMINATE,
                null, Constants.Flag.TRUE);
        HistoricProcessInstance historicProcessInstance = workflowInstanceService
                .queryHistoryProcessInstance(request.getProcessInstanceId());
        WfSysProcInfoEntity wfSysProcInfoEntity = getProcInfo(request.getProcessInstanceId(), "发起人终止");
        WfTaskAnnotationService wfTaskAnnotationService = workflowAnnotation.getService(historicProcessInstance.getProcessDefinitionKey());
        wfTaskAnnotationService.terminateTask(wfSysProcInfoEntity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteProcessInstance(ProcessInstanceRequest request) {
        List<String> processInstanceIds = request.getProcessInstanceIds();
        if (processInstanceIds == null) {
            processInstanceIds = new ArrayList<>();
        }
        if(StringUtils.isNotBlank(request.getProcessInstanceId())) {
            processInstanceIds.add(request.getProcessInstanceId());
        }
        AssertUtils.notEmpty(processInstanceIds, "流程id不能为空");
        workflowInstanceService.deleteProcessInstance(processInstanceIds);
        workflowInstanceService.deleteHistoryProcessInstance(processInstanceIds);
        ProcessEngineConfigurationImpl processEngineConfiguration = (ProcessEngineConfigurationImpl) processEngine
                .getProcessEngineConfiguration();
        CommandExecutor commandExecutor = processEngineConfiguration.getCommandExecutorTxRequired();
        List<String> finalProcessInstanceIds = processInstanceIds;
        commandExecutor.execute(new Command<Void>() {
            @Override
            public Void execute(CommandContext commandContext) {
                for (String processInstanceId : finalProcessInstanceIds) {
                    // 删除自定义数据
                    wfSysProcInfoService.delete(processInstanceId);
                }
                return null;
            }
        });
    }

    @Override
    public ProcessResponse queryProcessTrack(ProcessInstanceRequest request) {
        List<ProcessTrackTaskEntity> list = this.queryProcessTrackList(request);
        ProcessResponse.ProcessResponseBuilder response = ProcessResponse.builder();
        response.processTrack(list);
        response.nodes(queryFullNodes(list));
        return response.build();
    }

    @Override
    public List<ApprovalProcessTrace> queryProcessTrackV2(ProcessInstanceRequest request) {
        List<ApprovalProcessTrace> entities = new ArrayList<>();
        String processDefineId = request.getProcessDefineId();
        ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) workflowDefinitionService
                .findByProcessDefineId(processDefineId);
        //明细数据
        Map<String, TaskDefinition> taskDefinitionMap = processDefinition.getTaskDefinitions();
        //获取节点树
        ActivityImpl activity = processDefinition.getInitial();
        //获取出来的线
        List<PvmTransition> pvmTransitions = activity.getOutgoingTransitions();
        //当前节点信息
        String id = activity.getId();
        String type = activity.getProperties().get(new PropertyKey<>("type")).toString();
        String name = activity.getName();
        ApprovalProcessTrace.ApprovalProcessTraceBuilder approvalProcessTrace = ApprovalProcessTrace.builder();
        approvalProcessTrace.activityId(id).activityName(name).activityType(type);
        //查询历史活动ID
        HistoricProcessInstance historicProcessInstance = workflowInstanceService
                .queryHistoryProcessInstance(request.getProcessInstanceId());
        List<HistoricActivityInstance> historicActivityInstanceList = workflowInstanceService
                .queryHistoryServiceActivityInstance(request.getProcessInstanceId());
        Map<String, HistoricActivityInstance> historicActivityInstanceMap = historicActivityInstanceList.stream()
                .collect(Collectors.toMap(HistoricActivityInstance::getActivityId, Function.identity(), (x,y) -> y));
        Map<String, Object> variablesMap = new HashMap<>();
        if (historicProcessInstance != null && historicProcessInstance.getEndTime() != null) {
            List<HistoricVariableInstance> list = workflowInstanceService
                    .queryHistoryVariableInstance(request.getProcessInstanceId());
            if (!list.isEmpty()) {
                for (HistoricVariableInstance historicVariableInstance : list) {
                    variablesMap.put(historicVariableInstance.getName(), historicVariableInstance.getValue());
                }
            }
        } else {
            variablesMap = runtimeService.getVariables(request.getProcessInstanceId());
        }

        while(!CollectionUtils.isEmpty(pvmTransitions)) {
            int nextNodeCnt = pvmTransitions.size();
            //如果只有一个直接找下一个
            if (1 == nextNodeCnt) {
                ActivityImpl nextActivity = (ActivityImpl) pvmTransitions.get(0).getDestination();
                String nextActivityType = nextActivity.getProperties().get(new PropertyKey<>("type")).toString();
                //排他网关
                if("exclusiveGateway".equals(nextActivityType)) {
                    pvmTransitions = nextActivity.getOutgoingTransitions();
                    continue;
                }
                TaskDefinition taskDefinition = taskDefinitionMap.get(nextActivity.getActivityId().split("#")[0]);
                ApprovalProcessTrace nextApprovalProcessTrace = this.buildApprovalProcessTrace(pvmTransitions.get(0));
                nextApprovalProcessTrace.setNodeStat(this.getProcessNodeStat(nextApprovalProcessTrace.getActivityId(),
                        historicActivityInstanceMap));
                nextApprovalProcessTrace.setNodeName(null == taskDefinition ? null :
                        taskDefinition.getNameExpression().getExpressionText());
                entities.add(nextApprovalProcessTrace);
                pvmTransitions = nextActivity.getOutgoingTransitions();
            } else {
                PvmTransition defaultPvmTransition = null;
                Boolean defaultFlg = true;
                //如果是多个则根据全局找多个中的一个
                loop2 : for (PvmTransition pvmTransition : pvmTransitions) {
                    Object conditionText = pvmTransition.getProperties().get(new PropertyKey<>("conditionText"));
                    if (null == conditionText) {
                        defaultPvmTransition = pvmTransition;
                        continue;
                    }
                    boolean transitionBoolean = JuelUtils.checkFormDataByRuleEl(conditionText.toString(), variablesMap);
                    if (transitionBoolean) {
                        String nextActivityType = pvmTransition.getDestination()
                                .getProperties().get(new PropertyKey<>("type")).toString();
                        if ("exclusiveGateway".equals(nextActivityType)) {
                            pvmTransitions = pvmTransition.getDestination().getOutgoingTransitions();
                            defaultFlg = false;
                            break loop2;
                        }
                        TaskDefinition taskDefinition = taskDefinitionMap.get(
                                pvmTransition.getDestination().getId().split("#")[0]);
                        ApprovalProcessTrace nextApprovalProcessTrace = this.buildApprovalProcessTrace(pvmTransition);
                        nextApprovalProcessTrace.setNodeStat(
                                this.getProcessNodeStat(nextApprovalProcessTrace.getActivityId(),
                                        historicActivityInstanceMap));
                        nextApprovalProcessTrace.setNodeName(null == taskDefinition ? null :
                                taskDefinition.getNameExpression().getExpressionText());
                        entities.add(nextApprovalProcessTrace);
                        pvmTransitions = pvmTransition.getDestination().getOutgoingTransitions();
                        defaultFlg = false;
                        break loop2;
                    }
                }
                //如果是默认分支
                if (defaultFlg && null != defaultPvmTransition) {
                    TaskDefinition taskDefinition = taskDefinitionMap.get(
                            defaultPvmTransition.getDestination().getId().split("#")[0]);
                    ApprovalProcessTrace nextApprovalProcessTrace = this.buildApprovalProcessTrace(
                            defaultPvmTransition);
                    nextApprovalProcessTrace.setNodeStat(
                            this.getProcessNodeStat(nextApprovalProcessTrace.getActivityId(),
                                    historicActivityInstanceMap));
                    nextApprovalProcessTrace.setNodeName(null == taskDefinition ? null :
                            taskDefinition.getNameExpression().getExpressionText());
                    entities.add(nextApprovalProcessTrace);
                    pvmTransitions = defaultPvmTransition.getDestination().getOutgoingTransitions();
                }
            }
        }
        realProcessNodeStat(entities);
        transNodeName(entities);
        return entities;
    }

    @Override
    public WfSysProcInfoEntity getDetail(ProcessInstanceRequest request) {
        AssertUtils.notEmpty(request.getProcessInstanceId(), "流程实例id不能为空");
        WfSysProcInfoEntity wfSysProcInfoEntity = wfSysProcInfoService.selectOne(request.getProcessInstanceId());
        if (wfSysProcInfoEntity != null && StringUtils.isNotBlank(wfSysProcInfoEntity.getParamMap())) {
            wfSysProcInfoEntity.setParamMaps(JSON.parseObject(wfSysProcInfoEntity.getParamMap()));
        }
        return wfSysProcInfoEntity;
    }

    @Override
    public List<NextParticipantEntity> getParticipant(ProcessInstanceRequest request) {
        if (StringUtils.isBlank(request.getProcessInstanceId()) && request.getApplyTypes().isEmpty()) {
            return Collections.emptyList();
        }
        return participantService.findNextParticipant(request.getProcessInstanceId(), request.getApplyTypes());
    }

    @Override
    public Result queryInstance(Integer pageNum, Integer pageSize, ProcessTaskRequest request) {
        UserInfo userInfo = this.getCurrentUserInfo();
        String cropId = userInfo.getCorpId();
        request.setTenantId(cropId);
        ProcInstanceQuery instanceQuery = ProcTaskAssembler.createTodoProcInstanceQuery(request);
        return queryHandler.commonPageQuery(instanceQuery, pageNum, pageSize,
                new QueryResultHandler<ProcInstanceEntity, ProcInstanceEntity>() {
                    @Override
                    public ProcInstanceEntity handlerRecord(ProcInstanceEntity record) {
                        return record;
                    }
                });
    }


    public List<ProcessTrackTaskEntity> queryProcessTrackList(ProcessInstanceRequest request) {
        AssertUtils.notEmpty(request.getProcessInstanceId(), "流程实例id不能为空");
        List<ProcessTrackTaskEntity> list = new ArrayList<>();
        //历史任务节点
        List<ActHiTaskEntity> taskInstances = workflowInstanceService.findTaskListByProcessInstanceId(request.getProcessInstanceId());
        //历史活动节点数量
        Long activityInstances = workflowInstanceService.countHistoryServiceActivityInstance(request.getProcessInstanceId());
        if (CollectionUtils.isEmpty(taskInstances) && activityInstances == 0) {
            return list;
        }
        List<HistoricVariableInstance> variableInstances = workflowInstanceService.queryHistoryVariableInstance(request.getProcessInstanceId());
        if (Constants.Flag.TRUE.equals(request.getIsShowSuperProcess())) {
            HistoricProcessInstance historicProcessInstance = workflowInstanceService.queryHistoryProcessInstance(request.getProcessInstanceId());
            if (StringUtils.isNotBlank(historicProcessInstance.getSuperProcessInstanceId())) {
                ProcessInstanceRequest info = new ProcessInstanceRequest();
                info.setProcessInstanceId(historicProcessInstance.getSuperProcessInstanceId());
                info.setIsShowSuperProcess(Constants.Flag.TRUE);
                return queryProcessTrackList(info);
            }
        }
        // 获取当前流程定义模型信息，用于解析节点是否是会签
        if (CollectionUtils.isNotEmpty(taskInstances)) {
            String processDefineId = taskInstances.get(0).getProcDefId();
            String processInstanceId = taskInstances.get(0).getProcInstId();
            BpmnModelInstance modelInstance = workflowDefinitionService.findModel(processDefineId);
            Map<String, List<ActHiCommentEntity>> commentEntities = workflowInstanceService
                    .findCommentsByProcessInstanceId(processInstanceId);
            for (ActHiTaskEntity hiTask : taskInstances) {
                String multiFlag = workflowDefinitionService.getIsMulti(modelInstance, hiTask.getTaskDefKey());
                ProcessTrackTaskEntity.ProcessTrackTaskEntityBuilder taskEntity = ProcessTrackTaskEntity.builder()
                        .taskId(hiTask.getId())
                        .taskName(hiTask.getName())
                        .activityId(hiTask.getTaskDefKey())
                        .assignee(hiTask.getAssignee())
                        .assigneeName(hiTask.getAssigneeName())
                        .beginTime(hiTask.getStartTime())
                        .createTime(hiTask.getStartTime())
                        .endTime(hiTask.getEndTime())
                        .isMulti(multiFlag)
                        .deleteReason(hiTask.getDeleteReason());
                //如果是会签，且已经结束，没有处理人，则不做插入
                if ("true".equals(multiFlag) && StringUtils.isNotBlank(hiTask.getEndTime())
                        && StringUtils.isBlank(hiTask.getAssignee())) {
                    continue;
                }
                //如果结束时间为空，则为待办
                if (hiTask.getEndTime() == null) {
                    taskEntity.status(Constants.taskStatus.TODO);
                } else {
                    taskEntity.status(Constants.taskStatus.DONE);
                }
                List<ActHiCommentEntity> comments = commentEntities.get(hiTask.getId());
                taskEntity.comment(CollectionUtils.isEmpty(comments) ? "" : comments.get(0).getFullMsg());
                taskEntity.variables(getVariables(variableInstances, hiTask.getId()));
                getCandidate(hiTask, taskEntity);
                addTransferTrack(variableInstances, list, hiTask);
                list.add(taskEntity.build());
            }
        }
        //查询所有子流程任务
        if (Constants.Flag.TRUE.equals(request.getIsShowSubProcess())) {
            List<HistoricProcessInstance> childrenProcessInstances = workflowInstanceService.querySubHistoryProcessInstance(
                    request.getProcessInstanceId()
            );
            for (HistoricProcessInstance historicProcessInstance : childrenProcessInstances) {
                ProcessInstanceRequest info = new ProcessInstanceRequest();
                info.setProcessInstanceId(historicProcessInstance.getSuperProcessInstanceId());
                info.setIsShowSubProcess(Constants.Flag.TRUE);
                List<ProcessTrackTaskEntity> subTaskList = queryProcessTrackList(info);
                if (CollectionUtils.isNotEmpty(subTaskList)) {
                    list.addAll(subTaskList);
                }
            }
        }

        //对轨迹重新排序
        Collections.sort(list, new Comparator<ProcessTrackTaskEntity>() {
            @Override
            public int compare(ProcessTrackTaskEntity o1, ProcessTrackTaskEntity o2) {
                if (o1.getBeginTime().equals(o2.getBeginTime())) {
                    if (StringUtils.isNotBlank(o1.getEndTime()) && StringUtils.isNotBlank(o2.getEndTime())) {
                        return o1.getEndTime().compareTo(o2.getEndTime());
                    } else if (StringUtils.isBlank(o1.getEndTime()) && StringUtils.isNotBlank(o2.getEndTime())) {
                        return 1;
                    } else if (StringUtils.isNotBlank(o1.getEndTime()) && StringUtils.isBlank(o2.getEndTime())) {
                        return -1;
                    }else {
                        return 0;
                    }
                } else {
                    return o1.getBeginTime().compareTo(o2.getBeginTime());
                }
            }
        });
        return list;
    }

    private List<ApprovalProcessTrace> queryFullNodes(List<ProcessTrackTaskEntity> entities) {
        Stack<String> stackTaskName = new Stack<>();
        Stack<Object> stack = new Stack<>();
        for(ProcessTrackTaskEntity entity : entities) {
            while (stackTaskName.search(entity.getTaskName()) > 0) {
                stackTaskName.pop();
                stack.pop();
            }
            stackTaskName.push(entity.getTaskName());
            stack.push(entity);
        }
        List<ApprovalProcessTrace> list = new ArrayList<>();
        while (!stack.isEmpty()) {
            ProcessTrackTaskEntity entity = (ProcessTrackTaskEntity) stack.pop();
            ApprovalProcessTrace trace = ApprovalProcessTrace.builder()
                    .nodeName(entity.getTaskName())
                    .nodeStat(Constants.taskStatus.TODO.equals(entity.getStatus())  ? "1" : "2")
                    .build();
            list.add(trace);
        }
        Collections.reverse(list);
        return list;
    }

    private Map<String, Object> getVariables(List<HistoricVariableInstance> variableInstances,
                                             String taskId) {
        Map<String, Object> resultMap = new HashMap<>(1);
        if (variableInstances == null) {
            return resultMap;
        }
        for (HistoricVariableInstance variableInstance : variableInstances) {
            if (taskId.equals(variableInstance.getTaskId())) {
                resultMap.put(variableInstance.getName(), variableInstance.getValue());
            }
        }
        return resultMap;
    }

    private void getCandidate(ActHiTaskEntity hiTask,ProcessTrackTaskEntity.ProcessTrackTaskEntityBuilder taskEntity) {
        List<PostInfo> list = new ArrayList<>();
        if (hiTask.getAssignee() == null && StringUtils.isBlank(hiTask.getAssignee())
                && hiTask.getEndTime() == null) {
            TaskEntity task = (TaskEntity) workflowTaskService.findTask(hiTask.getId());
            if (task != null) {
                List<ActRuIdentityLinkEntity> actRuIdentityLinkEntityList = userParticipantService
                        .getAssignee(task.getId(), task.getTenantId());
                for(ActRuIdentityLinkEntity ruIdentityLinkEntity : actRuIdentityLinkEntityList) {
                    PostInfo postInfo = PostInfo.builder()
                            .type(ruIdentityLinkEntity.getType())
                            .jobCode(ruIdentityLinkEntity.getJobCode())
                            .orgCode(ruIdentityLinkEntity.getOrgCode())
                            .posCode(ruIdentityLinkEntity.getPosCode())
                            .roleCode(ruIdentityLinkEntity.getRoleCode())
                            .userId(ruIdentityLinkEntity.getUserId())
                            .build();
                    list.add(postInfo);
                }
                List<ParticipantUserEntity> participantUserEntities = userParticipantService.findUserByParticipants(list);
                List<String> assignee = new ArrayList<>();
                List<String> assigneeName = new ArrayList<>();
                for (ParticipantUserEntity participantUserEntity : participantUserEntities) {
                    assignee.add(participantUserEntity.getUserId());
                    assigneeName.add(participantUserEntity.getUserName());
                }
                taskEntity.assignee(String.join(",", assignee));
                taskEntity.assigneeName(String.join(",", assigneeName));
                taskEntity.postInfoList(list);
            }
        }
    }


    private void addTransferTrack(List<HistoricVariableInstance> variableInstances,
                                  List<ProcessTrackTaskEntity> entities,
                                  ActHiTaskEntity taskInstance) {
        Object track = null;
        for (HistoricVariableInstance variableInstance : variableInstances) {
            if (taskInstance.getId().equals(variableInstance.getTaskId()) &&
                    Constants._TRANSFER_TRACK.equals(variableInstance.getName())) {
                track = variableInstance.getValue();
            }
        }
        if (track == null) {
            return;
        }
        Map transfer = (Map) track;
        while((transfer != null)) {
            ProcessTrackTaskEntity.ProcessTrackTaskEntityBuilder taskEntity = ProcessTrackTaskEntity.builder()
                    .taskId(taskInstance.getId())
                    .taskName(taskInstance.getName())
                    .activityId(taskInstance.getTaskDefKey())
                    .assignee( (String) transfer.get("assignee"))
                    .assigneeName(ObjectUtils.isNotNull(transfer.get("assigneeName")) ? (String) transfer.get("assigneeName") : null)
                    .beginTime(taskInstance.getStartTime())
                    .createTime(taskInstance.getStartTime())
                    .endTime( (String) transfer.get("endTime"))
                    .comment( (String) transfer.get("comment"))
                    .deleteReason(ObjectUtils.isNotNull(transfer.get("deleteReason")) ? (String) transfer.get("deleteReason") : null)
                    .status(Constants.taskStatus.DONE);
            entities.add(taskEntity.build());
            transfer = (Map) transfer.get("next");
        }
    }

    private ApprovalProcessTrace buildApprovalProcessTrace(PvmTransition pvmTransition) {
        ActivityImpl nextActivity = (ActivityImpl) pvmTransition.getDestination();
        String nextActivityId = nextActivity.getId();
        String nextActivityName = nextActivity.getName();
        String nextActivityType = nextActivity.getProperties().get(new PropertyKey<>("type")).toString();
        String nextActivityParentId = pvmTransition.getSource().getId();
        //排他网关
        if (nextActivityParentId.startsWith("ExclusiveGateway")) {
            nextActivityParentId = pvmTransition.getSource().getIncomingTransitions().get(0).getSource().getId();
        }
        ApprovalProcessTrace.ApprovalProcessTraceBuilder approvalProcessTrace = ApprovalProcessTrace.builder();
        approvalProcessTrace.activityId(nextActivityId).activityName(nextActivityName).activityType(nextActivityType)
                .parentActivityId(nextActivityParentId);
        return approvalProcessTrace.build();
    }

    private String getProcessNodeStat(String activityId,
                                      Map<String, HistoricActivityInstance> historicActivityInstanceMap) {
        String actId = activityId.split("#")[0];
        HistoricActivityInstance historicActivityInstance = historicActivityInstanceMap.get(actId);
        if (null == historicActivityInstance) {
            return "0";
        }
        return null == historicActivityInstance.getEndTime() ? "1" : "2";
    }

    private void realProcessNodeStat(List<ApprovalProcessTrace> approvalProcessTraces) {
        boolean flag = false;
        for (ApprovalProcessTrace approvalProcessTrace : approvalProcessTraces) {
            if ("1".equals(approvalProcessTrace.getNodeStat())) {
                flag = true;
            } else if (flag && "2".equals(approvalProcessTrace.getNodeStat())) {
                approvalProcessTrace.setNodeStat("0");
            }
        }
    }

    private void transNodeName(List<ApprovalProcessTrace> traces) {
        if (traces != null && !traces.isEmpty()) {
            for (ApprovalProcessTrace trace : traces) {
                String nodeType = trace.getActivityType();
                TransNodeNameEnum transNodeNameEnum = TransNodeNameEnum.getEnum(nodeType);
                if (transNodeNameEnum != null) {
                    trace.setNodeName(transNodeNameEnum.getNodeName());
                }
            }
        }
    }


    /**
     * 根据流程实例获取流程信息
     * @param procInstId procInstId
     * @return WfSysProcInfoEntity
     */
    private WfSysProcInfoEntity getProcInfo(String procInstId, String comment) {
        WfSysProcInfoEntity wfSysProcInfoEntity = wfSysProcInfoService.selectOne(procInstId);
        if (wfSysProcInfoEntity != null && StringUtils.isNotBlank(wfSysProcInfoEntity.getParamMap())) {
            Map<String, Object> paramMap = JSON.parseObject(wfSysProcInfoEntity.getParamMap());
            wfSysProcInfoEntity.setParamMaps(paramMap);
            wfSysProcInfoEntity.setExtensionData(JSON.parseObject(JSON.toJSONString(paramMap.get(Constants.EXTENSION_DATA))));
            wfSysProcInfoEntity.setComment(comment);
        }
        return wfSysProcInfoEntity;
    }
}